package tmplter

// clcs:
//   clc:
//     row1:
//       field1: value11
//       field2: value12
//       ...
//     row2:
//       field1: value21
//       field2: value22
//       ...
//     ...
//   ...

import (
	"encoding/csv"
	"errors"
	"io"
	"regexp"
	"strings"
)

// Regex "{{.../}}" for finding collection pattern
var rgx = regexp.MustCompile(`\{\{[^\}\{]+\/\}\}`)

// Read collection from CSV text
func ReadCollection(s string, comma rune) (clc []map[string]string, err error) {
	r := strings.NewReader(s)
	csvr := csv.NewReader(r)
	csvr.Comma = comma
	clc_header := []string{}
	for {
		record, err := csvr.Read()
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
		if len(clc_header) == 0 {
			clc_header = record
			continue
		}
		c := map[string]string{}
		for i, v := range record {
			c[clc_header[i]] = v
		}
		clc = append(clc, c)
	}
	return clc, nil
}

// Parsing all patterns in template
func ParseTemplate(
	tpl string,
	clcs map[string][]map[string]string,
	filter map[string]string) (string, error) {
	for {
		ok, name, pattern, content, err := findPattern(tpl)
		if err != nil {
			return "", err
		}
		if ok {
			clc, clc_ok := clcs[name]
			if !clc_ok {
				return "", errors.New("? " + name)
			}
			new_content := ""
			for _, row := range clc {
				skip := false
				for k, v := range row {
					if f_v, f_ok := filter[k]; f_ok {
						if f_v != v {
							skip = true
							break
						}
					}
				}
				if skip {
					continue
				}
				new_filter := map[string]string{}
				for k, v := range filter {
					new_filter[k] = v
				}
				c := content
				for k_, v := range row {
					new_filter[k_] = v
					k := "{{" + k_ + "}}"
					c = strings.Replace(c, k, v, -1)
				}
				c, err = ParseTemplate(c, clcs, new_filter)
				if err != nil {
					return "", err
				}
				new_content += c
			}
			tpl = strings.Replace(tpl, pattern, new_content, -1)
		} else {
			break
		}
	}
	return tpl, nil
}

//Finding pattern and return his properties
// pattern: "{{name/}}content{{/name}}"
func findPattern(tpl string) (
	ok bool, name, pattern, content string, err error) {
	set := rgx.FindString(tpl)
	if set == "" {
		return false, "", "", "", nil
	}
	set_ix := strings.Index(tpl, set)
	name = set[2 : len(set)-3]
	end := "{{/" + name + "}}"
	end_ix := strings.Index(tpl, end)
	if end_ix == -1 {
		return false, "", "", "", errors.New("? " + end)
	}
	pattern = tpl[set_ix : end_ix+len(end)]
	content = tpl[set_ix+len(set) : end_ix]
	return true, name, pattern, content, nil
}
